// Render Target Texture OpenGL
// (c) jimon game studio

#include "CRenderTargetTexture_OpenGL.h"

#ifdef JE_RENDER_OPENGL

#include "CTexture_OpenGL.h"

namespace je
{
	namespace video
	{
		//! Constructor
		CRenderTargetTexture_OpenGL::CRenderTargetTexture_OpenGL(CRender_OpenGL_Extensions * NewExtensions,OpenGLWorkMode WorkMode)
			:Extensions(NewExtensions),FrameBufferObject(NULL),CurrentWorkMode(WorkMode)
		{
			for(s32 i=0;i<JE_MAX_RENDERTEXTURETARGET_TEXTURES;i++)
				CurrentTextures[i] = NULL;

			if(CurrentWorkMode != OWM_11)
				Extensions->GenerateFramebuffers(1,&FrameBufferObject);
		}

		//! Destructor
		CRenderTargetTexture_OpenGL::~CRenderTargetTexture_OpenGL()
		{
			for(s32 i=0;i<JE_MAX_RENDERTEXTURETARGET_TEXTURES;i++)
				if(CurrentTextures[i])
					CurrentTextures[i]->Drop();

			if(CurrentWorkMode != OWM_11)
				Extensions->DeleteFramebuffers(1,&FrameBufferObject);
		}

		//! Attach Texture
		u1 CRenderTargetTexture_OpenGL::AttachTexture(ITexture * Texture,RenderTargetTextureLayer Layer)
		{
			if(CurrentWorkMode == OWM_11)
				return false;

			Extensions->BindFrameBuffer(GL_FRAMEBUFFER,FrameBufferObject);

			u1 AttachError = true;

			if(CurrentTextures[Layer])
				CurrentTextures[Layer]->Drop();

			CurrentTextures[Layer] = Texture;
			if(CurrentTextures[Layer])
			{
				CurrentTextures[Layer]->Grab();
				if(static_cast<CTexture_OpenGL*>(Texture)->IsRenderBuffer())
					Extensions->SetFrameBufferRenderBuffer(GL_FRAMEBUFFER,ConvertLayerToAttachment(Layer),GL_RENDERBUFFER,static_cast<CTexture_OpenGL*>(Texture)->GetTextureOpenGLID());
				else
					Extensions->SetFrameBufferTexture2D(GL_FRAMEBUFFER,ConvertLayerToAttachment(Layer),static_cast<CTexture_OpenGL*>(Texture)->GetTextureOpenGLType(),static_cast<CTexture_OpenGL*>(Texture)->GetTextureOpenGLID(),0);

				GLenum FrameBufferStatus = Extensions->ChechFrameBufferStatus(GL_FRAMEBUFFER);

				switch(FrameBufferStatus)
				{
				case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
					JELOG_E("FBO : Incomplete Attachment")
					break;
				case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
					JELOG_E("FBO : Incomplete Draw Buffer")
					break;
				case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
					JELOG_E("FBO : Incomplete Read Buffer")
					break;
				case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
					JELOG_E("FBO : Incomplete Missing Attachment")
					break;
				case GL_FRAMEBUFFER_UNSUPPORTED:
					JELOG_E("FBO : Unsupported")
					break;
				default:
					AttachError = false;
					break;
				}
			}
			else
				Extensions->SetFrameBufferTexture2D(GL_FRAMEBUFFER,ConvertLayerToAttachment(Layer),GL_TEXTURE_2D,NULL,0);
			
			GLenum * DrawBuffers = NULL;
			JENEW_A(DrawBuffers,GLenum,JE_MAX_RENDERTEXTURETARGET_TEXTURES)
			s32 DrawBuffersCount = 0;

			for(s32 i=0;i<JE_MAX_RENDERTEXTURETARGET_TEXTURES;i++)
				if(CurrentTextures[i] && (i < RTTL_DEPTH))
					DrawBuffers[DrawBuffersCount++] = GL_COLOR_ATTACHMENT0+i;

			Extensions->DrawBuffers(DrawBuffersCount,DrawBuffers);
			JEDELETE_A(DrawBuffers)

			Extensions->BindFrameBuffer(GL_FRAMEBUFFER,NULL);

			return !AttachError;
		}

		//! DeAttach Texture
		void CRenderTargetTexture_OpenGL::DeAttachTexture(RenderTargetTextureLayer Layer)
		{
			AttachTexture(NULL,Layer);
		}

		//! Get Texture
		ITexture * CRenderTargetTexture_OpenGL::GetTexture(RenderTargetTextureLayer Layer)
		{
			return CurrentTextures[Layer];
		}

		//! Copy To Buffer
		void CRenderTargetTexture_OpenGL::CopyToBuffer(IRenderTargetTexture * Destination)
		{
			Extensions->BindFrameBuffer(GL_READ_FRAMEBUFFER,FrameBufferObject);
			Extensions->BindFrameBuffer(GL_DRAW_FRAMEBUFFER,static_cast<CRenderTargetTexture_OpenGL*>(Destination)->GetFBOId());

			u1 EnableDepth = CurrentTextures[RTTL_DEPTH]?true:false;
			for(s32 i=0;i<JE_MAX_RENDERTEXTURETARGET_TEXTURES;i++)
				if(CurrentTextures[i] && (i < RTTL_DEPTH))
				{
					Extensions->SetReadBuffer(GL_COLOR_ATTACHMENT0+i);
					Extensions->SetDrawBuffer(GL_COLOR_ATTACHMENT0+i);
					jeVector2di Size = CurrentTextures[i]->GetSize();
					
					Extensions->BlitFrameBuffers(0,0,Size.X,Size.Y,0,0,Size.X,Size.Y,EnableDepth?(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT):GL_COLOR_BUFFER_BIT,GL_NEAREST);

					if(EnableDepth)
						EnableDepth = false;
				}
			Extensions->BindFrameBuffer(GL_READ_FRAMEBUFFER,0);
			Extensions->BindFrameBuffer(GL_DRAW_FRAMEBUFFER,0);
		}

		//! Bind
		void CRenderTargetTexture_OpenGL::Bind()
		{
			if(CurrentWorkMode != OWM_11)
				Extensions->BindFrameBuffer(GL_FRAMEBUFFER,FrameBufferObject);
		}

		//! UnBind
		void CRenderTargetTexture_OpenGL::UnBind()
		{
			if(CurrentWorkMode != OWM_11)
				Extensions->BindFrameBuffer(GL_FRAMEBUFFER,NULL);

			//for(s32 i=0;i<JE_MAX_MATERIAL_TEXTURES;i++)
			//	if(CurrentTextures[i])
			//	{
			//		glBindTexture(GL_TEXTURE_2D,static_cast<CTexture_OpenGL*>(CurrentTextures[i])->GetTextureOpenGLID());
			//		Extensions->GenerateMipmap(GL_TEXTURE_2D);
			//		glBindTexture(GL_TEXTURE_2D,NULL);
			//	}
		}

	}
}

#endif
